"""
数据库模块：处理数据库相关的操作
包括数据库初始化、任务管理、日志记录等

主要功能：
1. 数据库初始化：创建必要的表结构
2. 任务管理：插入、更新、查询任务信息
3. 日志记录：记录用户操作日志
4. 文件管理：管理下载和裁剪后的文件信息
"""

import os
import sqlite3
import json
from pathlib import Path
from datetime import datetime
from typing import List, Dict, Any, Optional, Tuple
from bbdown.core.logger import Logger

from .constants import DB_PATH

logger = Logger()

def init_db():
    """
    初始化数据库，创建必要的表
    
    创建以下表：
    1. task: 存储任务信息
    2. operation_log: 存储操作日志
    3. result: 存储结果文件信息
    """
    conn = sqlite3.connect(DB_PATH)
    c = conn.cursor()
    
    # 创建任务表：存储下载和裁剪任务的基本信息
    c.execute('''
        CREATE TABLE IF NOT EXISTS task (
            id TEXT PRIMARY KEY,          -- 任务ID，使用UUID
            user_id TEXT,                 -- 用户ID
            type TEXT,                    -- 任务类型：download/cut/batch_cut
            params TEXT,                  -- 任务参数，JSON格式
            status TEXT,                  -- 任务状态：pending/running/finished/error
            result TEXT,                  -- 任务结果，JSON格式
            created_at TIMESTAMP,         -- 创建时间
            updated_at TIMESTAMP          -- 更新时间
        )
    ''')
    
    # 创建操作日志表：记录用户的所有操作
    c.execute('''
        CREATE TABLE IF NOT EXISTS operation_log (
            id INTEGER PRIMARY KEY AUTOINCREMENT,  -- 日志ID
            user_id TEXT,                         -- 用户ID
            task_id TEXT,                         -- 关联的任务ID
            action TEXT,                          -- 操作类型
            detail TEXT,                          -- 操作详情，JSON格式
            ip TEXT,                              -- 用户IP地址
            created_at TIMESTAMP                  -- 创建时间
        )
    ''')
    
    # 创建结果文件表：存储任务产生的文件信息
    c.execute('''
        CREATE TABLE IF NOT EXISTS result (
            id INTEGER PRIMARY KEY AUTOINCREMENT,  -- 记录ID
            task_id TEXT,                         -- 关联的任务ID
            file_name TEXT,                       -- 文件名
            file_path TEXT,                       -- 文件路径
            file_size INTEGER,                    -- 文件大小（字节）
            file_type TEXT,                       -- 文件类型
            created_at TIMESTAMP,                 -- 创建时间
            FOREIGN KEY (task_id) REFERENCES task (id)  -- 外键约束
        )
    ''')
    
    conn.commit()
    conn.close()

def insert_task(task_id: str, user_id: str, task_type: str, params: dict) -> None:
    """
    插入新任务
    
    参数：
        task_id (str): 任务ID，使用UUID生成
        user_id (str): 用户ID，用于关联用户
        task_type (str): 任务类型，如download/cut/batch_cut
        params (dict): 任务参数，包含任务所需的所有信息
    """
    conn = sqlite3.connect(DB_PATH)
    c = conn.cursor()
    now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    c.execute(
        'INSERT INTO task (id, user_id, type, params, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)',
        (task_id, user_id, task_type, json.dumps(params), 'pending', now, now)
    )
    conn.commit()
    conn.close()

def update_task_status(task_id: str, status: str, result: dict = None) -> None:
    """
    更新任务状态
    
    参数：
        task_id (str): 任务ID
        status (str): 新状态，可选值：pending/running/finished/error
        result (dict): 任务结果，包含任务执行的结果信息
    """
    conn = sqlite3.connect(DB_PATH)
    c = conn.cursor()
    now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    if result:
        c.execute(
            'UPDATE task SET status = ?, result = ?, updated_at = ? WHERE id = ?',
            (status, json.dumps(result), now, task_id)
        )
    else:
        c.execute(
            'UPDATE task SET status = ?, updated_at = ? WHERE id = ?',
            (status, now, task_id)
        )
    conn.commit()
    conn.close()

def get_task(task_id: str) -> Optional[Tuple]:
    """
    获取任务信息
    
    参数：
        task_id (str): 任务ID
        
    返回：
        Optional[Tuple]: 任务信息元组，包含以下字段：
            - id: 任务ID
            - user_id: 用户ID
            - type: 任务类型
            - params: 任务参数（JSON字符串）
            - status: 任务状态
            - result: 任务结果（JSON字符串）
            - created_at: 创建时间
            - updated_at: 更新时间
    """
    conn = sqlite3.connect(DB_PATH)
    c = conn.cursor()
    c.execute('SELECT * FROM task WHERE id = ?', (task_id,))
    row = c.fetchone()
    conn.close()
    return row

def insert_log(user_id: str, task_id: str, action: str, detail: dict, ip: str) -> None:
    """
    插入操作日志
    
    参数：
        user_id (str): 用户ID
        task_id (str): 关联的任务ID
        action (str): 操作类型，如download/cut/rename等
        detail (dict): 操作详情，包含操作的具体信息
        ip (str): 用户IP地址，用于追踪
    """
    conn = sqlite3.connect(DB_PATH)
    c = conn.cursor()
    now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    c.execute(
        'INSERT INTO operation_log (user_id, task_id, action, detail, ip, created_at) VALUES (?, ?, ?, ?, ?, ?)',
        (user_id, task_id, action, json.dumps(detail), ip, now)
    )
    conn.commit()
    conn.close()

def insert_result(task_id: str, file_name: str, file_path: str, file_size: int, file_type: str) -> None:
    """
    插入结果文件记录
    
    参数：
        task_id (str): 关联的任务ID
        file_name (str): 文件名
        file_path (str): 文件完整路径
        file_size (int): 文件大小（字节）
        file_type (str): 文件MIME类型
    """
    conn = sqlite3.connect(DB_PATH)
    c = conn.cursor()
    now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    c.execute(
        'INSERT INTO result (task_id, file_name, file_path, file_size, file_type, created_at) VALUES (?, ?, ?, ?, ?, ?)',
        (task_id, file_name, file_path, file_size, file_type, now)
    )
    conn.commit()
    conn.close()

def update_task_filename(task_id: str, new_filename: str) -> None:
    """
    更新任务文件名
    
    参数：
        task_id (str): 任务ID
        new_filename (str): 新文件名
        
    说明：
        文件名存储在task表的params字段中（JSON格式）
    """
    conn = sqlite3.connect(DB_PATH)
    c = conn.cursor()
    
    # 获取当前params
    c.execute('SELECT params FROM task WHERE id = ?', (task_id,))
    row = c.fetchone()
    if not row or not row[0]:
        conn.close()
        return
        
    try:
        # 解析params
        params = json.loads(row[0])
        # 更新文件名
        params['filename'] = new_filename
        # 保存更新后的params
        c.execute(
            'UPDATE task SET params = ? WHERE id = ?',
            (json.dumps(params, ensure_ascii=False), task_id)
        )
        conn.commit()
    except Exception as e:
        logger.error(f"更新任务文件名失败: {str(e)}")
    finally:
        conn.close()

def update_result_filename(task_id: str, old_filename: str, new_filename: str) -> None:
    """
    更新结果文件名
    
    参数：
        task_id (str): 任务ID
        old_filename (str): 原文件名
        new_filename (str): 新文件名
        
    说明：
        同时更新result表中的文件名和task表中的params字段
    """
    conn = sqlite3.connect(DB_PATH)
    c = conn.cursor()
    
    try:
        # 更新result表中的文件名
        c.execute(
            'UPDATE result SET file_name = ? WHERE task_id = ? AND file_name = ?',
            (new_filename, task_id, old_filename)
        )
        
        # 更新task表中的params字段
        c.execute('SELECT params FROM task WHERE id = ?', (task_id,))
        row = c.fetchone()
        if row and row[0]:
            try:
                params = json.loads(row[0])
                params['filename'] = new_filename
                c.execute(
                    'UPDATE task SET params = ? WHERE id = ?',
                    (json.dumps(params, ensure_ascii=False), task_id)
                )
            except Exception as e:
                logger.error(f"更新task表params失败: {str(e)}")
        
        conn.commit()
    except Exception as e:
        logger.error(f"更新文件名失败: {str(e)}")
        raise
    finally:
        conn.close()

def get_task_files(task_id: str) -> List[Dict[str, Any]]:
    """
    获取任务相关的文件列表
    
    参数：
        task_id (str): 任务ID
        
    返回：
        List[Dict[str, Any]]: 文件信息列表，每个文件包含以下信息：
            - file_name: 文件名
            - file_path: 文件路径
            - file_size: 文件大小
            - file_type: 文件类型
            - download_url: 下载URL
    """
    conn = sqlite3.connect(DB_PATH)
    c = conn.cursor()
    c.execute('SELECT file_name, file_path, file_size, file_type FROM result WHERE task_id = ?', (task_id,))
    files = c.fetchall()
    conn.close()
    
    return [
        {
            "file_name": f[0],
            "file_path": f[1],
            "file_size": f[2],
            "file_type": f[3],
            "download_url": f"/api/download/file/{task_id}/{f[0]}"
        }
        for f in files
    ]

def get_tasks(q: str = '', page: int = 1, page_size: int = 20) -> Dict[str, Any]:
    """
    获取任务列表，支持分页和搜索
    
    参数：
        q (str): 搜索关键词，用于搜索任务ID、类型或状态
        page (int): 页码，从1开始
        page_size (int): 每页显示的任务数量
        
    返回：
        Dict[str, Any]: 包含以下信息：
            - total: 总任务数
            - page: 当前页码
            - page_size: 每页数量
            - data: 任务列表，每个任务包含完整信息和相关文件
    """
    conn = sqlite3.connect(DB_PATH)
    c = conn.cursor()
    
    # 构建查询条件
    sql = "SELECT * FROM task"
    params = []
    if q:
        sql += " WHERE id LIKE ? OR type LIKE ? OR status LIKE ?"
        qlike = f"%{q}%"
        params = [qlike, qlike, qlike]
    
    # 添加分页
    sql += " ORDER BY created_at DESC LIMIT ? OFFSET ?"
    params += [page_size, (page-1)*page_size]
    
    # 执行查询
    c.execute(sql, params)
    rows = c.fetchall()
    desc = [col[0] for col in c.description]
    
    # 获取总数
    count_sql = "SELECT COUNT(*) FROM task" + (" WHERE id LIKE ? OR type LIKE ? OR status LIKE ?" if q else "")
    c.execute(count_sql, params[:-2] if q else [])
    total = c.fetchone()[0]
    
    # 获取文件信息
    tasks = []
    for row in rows:
        task = dict(zip(desc, row))
        task['download_files'] = get_task_files(task['id'])
        tasks.append(task)
    
    conn.close()
    
    return {
        "total": total,
        "page": page,
        "page_size": page_size,
        "data": tasks
    }

def get_logs(q: str = '', page: int = 1, page_size: int = 20) -> Dict[str, Any]:
    """
    获取操作日志列表，支持分页和搜索
    
    参数：
        q (str): 搜索关键词，用于搜索操作类型或详情
        page (int): 页码，从1开始
        page_size (int): 每页显示的日志数量
        
    返回：
        Dict[str, Any]: 包含以下信息：
            - total: 总日志数
            - page: 当前页码
            - page_size: 每页数量
            - data: 日志列表
    """
    conn = sqlite3.connect(DB_PATH)
    c = conn.cursor()
    
    # 构建查询条件
    sql = "SELECT * FROM operation_log"
    params = []
    if q:
        sql += " WHERE action LIKE ? OR detail LIKE ?"
        qlike = f"%{q}%"
        params = [qlike, qlike]
    
    # 添加分页
    sql += " ORDER BY created_at DESC LIMIT ? OFFSET ?"
    params += [page_size, (page-1)*page_size]
    
    # 执行查询
    c.execute(sql, params)
    rows = c.fetchall()
    desc = [col[0] for col in c.description]
    
    # 获取总数
    count_sql = "SELECT COUNT(*) FROM operation_log" + (" WHERE action LIKE ? OR detail LIKE ?" if q else "")
    c.execute(count_sql, params[:-2] if q else [])
    total = c.fetchone()[0]
    
    conn.close()
    
    return {
        "total": total,
        "page": page,
        "page_size": page_size,
        "data": [dict(zip(desc, row)) for row in rows]
    }

def get_log(log_id: int) -> Optional[Dict[str, Any]]:
    """
    获取单个操作日志
    
    参数：
        log_id (int): 日志ID
        
    返回：
        Optional[Dict[str, Any]]: 日志信息字典，包含以下字段：
            - id: 日志ID
            - user_id: 用户ID
            - task_id: 关联的任务ID
            - action: 操作类型
            - detail: 操作详情（JSON字符串）
            - ip: 用户IP地址
            - created_at: 创建时间
    """
    conn = sqlite3.connect(DB_PATH)
    c = conn.cursor()
    c.execute("SELECT * FROM operation_log WHERE id = ?", (log_id,))
    row = c.fetchone()
    desc = [col[0] for col in c.description]
    conn.close()
    
    if not row:
        return None
        
    return dict(zip(desc, row))

def get_file_info(task_id: str, file_name: str) -> Optional[Tuple]:
    """
    获取文件信息
    
    参数：
        task_id (str): 任务ID
        file_name (str): 文件名
        
    返回：
        Optional[Tuple]: 文件信息元组，包含以下字段：
            - file_path: 文件路径
            - file_type: 文件类型
    """
    conn = sqlite3.connect(DB_PATH)
    c = conn.cursor()
    c.execute(
        "SELECT file_path, file_type FROM result WHERE task_id = ? AND file_name = ?",
        (task_id, file_name)
    )
    row = c.fetchone()
    conn.close()
    return row 